from twisted.internet.protocl import DatagramProtocol, Protocol, Factory, ClientFactory
import cPickle as pickle

class TCPProtocol(Protocol):
    def connectionMade(self):
        self.parent.connectionMade(self)

    def connectionLost(self):
        self.parent.connectionLost(self)
    
    def dataRecieved(self, data):
        #since we don't know if this is a complete packet or not, we need to cache it....
        self.parent.cacheData(data)

class UDPProtocol(DatagramProtocol):
    def __init__(self, parent):
        self.parent = parent
    def datagramReceived(self, data, (host, port)):
        #we don't really care about host or port right now
        self.parent.handleUnit(data) # Throw the data straight at the unit handler since datagrams are fun like that.

class TCPClientFactory(ClientFactory):
    def buildProtocol(self, addr):
        self._protocol = TCPProtocol(self.parent)
        return self._protocol
        
    def clientConnectionRefused(self, connector, reason):
        self.parent.connectionRefused()


class MultiProtocol:
    cache = ''
    server = False
    tcpnet = None
    udpnet = None
    factory = None
    addr = 0
    l = 0

    def startServer(self, data):
        self.server = True
        self.factory = Factory()
        
        
    def cacheData(self, data):
        self.cache += data
#        print "Adding:", len(data), "Cache len:", len(self.cache)
        if not self.l:
            self.l = ord(self.cache[0])

#        print "We want:", self.l
        
        if len(self.cache) >= self.l + 2:
#            print self.l, "flushed"
            unit = self.handleUnit(self.cache[1:self.l+2])
            self.routeUnit(unit[0], unit[1])
            self.cache = self.cache[self.l + 3:]
            self.l = 0
#            print len(self.cache), "remain in cache"              
            return unit
        
        return None

    def handleUnit(self, data):
        id = ord(data[0])
        data = pickle.loads(data[1:])
        return id, data

    def routeUnit(self, id, data):
        pass                    # Overwrite this function!

    
    def getPacket(self, id, data):
        datas = pickle.dumps(data)
        datas = chr(len(datas)) + chr(id) + datas #Prepend length of data string and id selector
#        print "Packet:", datas
        return datas
        
    def send(self, id, data):
        packet = getPacket(id, data)
        self.tcpnet.transport.write(packet)
